/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef RTC_DRV_H
#define RTC_DRV_H

/*!
 * @file rtc_drv.h
 * @brief This file declares rtc driver interfaces
 */

/*!
 * @addtogroup rtc_drv
 * @{
 */

/*******Includes***************************************************************/
#include <stdint.h>
#include <stdbool.h>
#include "errcodes.h"

/*******Definitions************************************************************/
/*!
 * @brief RTC clock source
 */
#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
typedef enum {
    RTC_CLK_SRC_LSI = 0U,   /*!< RTC clock source is LSI */
    RTC_CLK_SRC_PERI0 = 1U, /*!< RTC clock source is PERI0 */
    RTC_CLK_SRC_HSE = 2U,   /*!< RTC clock source is HSE */
    RTC_CLK_SRC_LSE = 3U    /*!< RTC clock source is LSE */
} rtc_clk_src_t;
#else
typedef enum {
    RTC_CLK_SRC_LSI = 0U,   /*!< RTC clock source is LSI */
    RTC_CLK_SRC_APB = 1U,   /*!< RTC clock source is APB */
    RTC_CLK_SRC_HSE = 2U,   /*!< RTC clock source is HSE */
    RTC_CLK_SRC_LSE = 3U    /*!< RTC clock source is LSE */
} rtc_clk_src_t;
#endif

/*!
 * @brief RTC clock out select
 */
typedef enum {
    RTC_CLK_OUT_PASS_THROUGH_CLK_IN = 0x00U,    /*!< Clock output RTC clock in    */
    RTC_CLK_OUT_PRESCALED_CLK       = 0x01U     /*!< Clock output prescaled clock */
} rtc_clk_out_t;

/*!
 * @brief RTC Callback type
 */
typedef void (*rtc_callback_t)(uint32_t instance, void* param);

/*!
 * @brief RTC configuration structure
 */
typedef struct {
    rtc_clk_src_t clockSoruce;                  /*!< Clock source selected                     */
    uint16_t prescaler;                         /*!< Prescaler value of RTC                    */
    int8_t compensation;                        /*!< Compensation value of RTC                 */
    uint8_t compensationInterval;               /*!< Compensation interval of RTC              */
    rtc_clk_out_t clockOutSelect;               /*!< Clock output source selected              */
    bool clockOutEnable;                        /*!< Enable clock output                       */
    bool ICMTriggerEnable;                      /*!< Enable ICM Trigger                        */
} rtc_config_t;

/*!
 * @brief RTC Time/Date structure
 */
typedef struct {
    uint16_t year;      /*!< Year    */
    uint16_t month;     /*!< Month   */
    uint16_t day;       /*!< Day     */
    uint16_t hour;      /*!< Hour    */
    uint16_t minutes;   /*!< Minutes */
    uint8_t seconds;    /*!< Seconds */
} rtc_timedate_t;

/*!
 * @brief RTC alarm settings
 */
typedef struct {
    rtc_timedate_t alarmTime;                   /*!< Target alarm time                  */
    uint32_t repetitionInterval;                /*!< Interval of repeatition in seconds */
    uint32_t numberOfRepeats;                   /*!< Number of alarm repeats            */
    bool repeatForever;                         /*!< Repeat forever                     */
    bool alarmIntEnable;                        /*!< Enable alarm interrupt             */
    rtc_callback_t alarmCallback;               /*!< Point to callback function         */
    void* callbackParam;                        /*!< Point to callback parameters       */
} rtc_alarm_config_t;

/*!
 * @brief RTC periodic alarm settings
 */
typedef struct {
    uint32_t interval;                          /*!< Interval of periodic alarm      */
    bool periodicAlarmIntEnable;                /*!< Enable periodic alarm interrupt */
    rtc_callback_t periodicAlarmCallback;       /*!< Point to callback function      */
    void* callbackParam;                        /*!< Point to callback parameters    */
} rtc_periodic_alarm_config_t;

/*!
 * @brief RTC overflow settings
 */
typedef struct {
    bool overflowIntEnable;                     /*!< Enable counter overflow interrupt function*/
    rtc_callback_t overflowCallback;            /*!< Point to overflow callback                */
    void* callbackParam;                        /*!< Point to overflow callback parameters     */
} rtc_overflow_config_t;

/*******APIs*******************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief Initialize RTC instance according to the given configuration
 *
 * @param[in] instance: Number of RTC
 * @param[in] config: RTC configuration
 * @return ERR_SUCCESS: if the operation was success
 *         ERR_RTC_ALREADY_RUNNING: the RTC is already running
 */
errcode_t RTC_Init(uint32_t instance, const rtc_config_t* config);

/*!
 * @brief Deinitialize RTC instance
 *
 * @param[in] instance: Number of RTC
 * @return None
 */
void RTC_Deinit(uint32_t instance);

/*!
 * @brief Get default RTC configuration via the configuration point passed as parameter
 *
 * @param[out] config: Point of a rtc_config_t used to get the default configuration
 * @return None
 */
void RTC_GetDefaultConfig(rtc_config_t* config);

/*!
 * @brief Set counter of RTC according to the given time, this function will calculate the
          seconds elapsed since 1970/01/01 00:00:00 to the given time and configure it to
          the counter of RTC
 *
 * @param[in] instance: Number of RTC
 * @param[in] time: Point to a date and time setting
 * @return ERR_SUCCESS: If the operation was success
 *         ERR_ERROR: If the operation was fail
 */
errcode_t RTC_SetTimeDate(uint32_t instance, const rtc_timedate_t* time);

/*!
 * @brief Get current time according to the counter of RTC, the counter value is the seconds
 *        elapsed since 1970/01/01 00:00:00 to this moment, this function will convert the seconds
 *        to time and date
 *
 * @param[in] instance: Number of RTC
 * @param[out] timeDate: Point to a rtc_timedate_t struct used to save time
 * @return ERR_SUCCESS: If the operation was success
 *         ERR_ERROR: If the operation was fail
 */
errcode_t RTC_GetCurrentTimeDate(uint32_t instance, rtc_timedate_t* timeDate);

/*!
 * @brief Start counter of RTC
 *
 * @param[in] instance: Number of RTC
 * @return ERR_SUCCESS: The counter has been started successfully
 *         ERR_RTC_INVALID_STATE: The counter is already running
 */
errcode_t RTC_StartCounter(uint32_t instance);

/*!
 * @brief Stop counter of RTC
 *
 * @param[in] instance: Number of RTC
 * @return ERR_SUCCESS: The counter has been stopped successfully
 *         ERR_ERROR: The counter is already stopped
 */
errcode_t RTC_StopCounter(uint32_t instance);

/*!
 * @brief Check whether RTC is enabled or not
 *
 * @param[in] instance: Number of RTC
 * @return True if RTC is already enabled, false if not
 */
bool RTC_IsEnabled(uint32_t instance);

/*!
 * @brief Configurate compensation of RTC
 *
 * @param[in] instance: Number of RTC
 * @param[in] compensation: Compensation value of RTC, compensation is a signed value, for example:
 *                          -1     - Time prescaler overflows every 32769 clock cycles
 *                          -127   - Time prescaler overflows every 32641 clock cycles
 *                          0      - Time prescaler overflows every 32768 clock cycles
 *                          127    - Time prescaler overflows every 32895 clock cycles
 * @param[in] interval: Compensation interval of RTC, control how frequently the compensation will be adjust, for example:
 *                      if compensation is 100, interval is 10, the 100 cycle compensation will be despersion to 10
 *                      prescaler overflow processes
 * @return ERR_SUCCESS: If the operation was success
 *         ERR_ERROR: If the operation was fail
 */
errcode_t RTC_ConfigTimeCompensation(uint32_t instance, int8_t compensation, uint8_t interval);

/*!
 * @brief Get compensation value of RTC
 *
 * @param[in] instance: Number of RTC
 * @param[out] compensation: Current compensation value of RTC
 * @param[out] interval: Current compensation interval of RTC
 * @return None
 */
void RTC_GetTimeCompensation(uint32_t instance, int8_t* compensation, uint8_t* interval);

/*!
 * @brief Set alarm of RTC according to configuration passed as parameter
 *
 * @param[in] instance: Number of RTC
 * @param[in] alarmConfig: Alarm configuration, this point will be reserved
 *                         for asynchronously use, it must be pointed to static or global memory
 * @return ERR_SUCCESS: If the operation was success
 *         ERR_ERROR: If the operation was fail
 */
errcode_t RTC_ConfigAlarm(uint32_t instance, rtc_alarm_config_t* alarmConfig);

/*!
 * @brief Stop alarm of RTC
 *
 * @param[in] instance: Number of RTC
 * @return None
 */
void RTC_StopAlarm(uint32_t instance);

/*!
 * @brief Get alarm configuration of RTC
 *
 * @param[in] instance: Number of RTC
 * @param[out] alarmConfig: Point to a structure used to get alarm configuration
 * @return ERR_SUCCESS: If the operation was success
 *         ERR_ERROR: If the operation was fail
 */
errcode_t RTC_GetAlarmConfig(uint32_t instance, rtc_alarm_config_t* alarmConfig);

/*!
 * @brief Check if a alarm event is pending
 *
 * @param[in] instance: Number of RTC
 * @return True if a alarm is going to occur, false if not
 */
bool RTC_IsAlarmPending(uint32_t instance);

/*!
 * @brief Get the time of next on going alarm
 *
 * @param[in] instance: Number of RTC
 * @param[in] alarmTime: Point to a structure used to get next alarm alarm Time/Date
 * @return ERR_SUCCESS: If the operation was success
 *         ERR_ERROR: If the operation was fail
 */
errcode_t RTC_GetNextAlarmTime(uint32_t instance, rtc_timedate_t* alarmTime);

/*!
 * @brief Set periodic alarm of RTC accroding to configuration passed as parameter
 *
 * @param[in] instance: Number of RTC
 * @param[in] alarmConfig: Periodic alarm configuration, this point will be reserved
 *                         for asynchronously use, it must be pointed to static or global memory
 * @return ERR_SUCCESS: If the operation was success
 *         ERR_ERROR: If the operation was fail
 */
errcode_t RTC_ConfigPeriodicAlarm(uint32_t instance, rtc_periodic_alarm_config_t* alarmConfig);

/*!
 * @brief Stop periodic alarm of RTC
 *
 * @param[in] instance: Number of RTC
 * @return None
 */
void RTC_StopPeriodicAlarm(uint32_t instance);

/*!
 * @brief Get periodic alarm configuration of RTC
 *
 * @param[in] instance: Number of RTC
 * @param[out] alarmConfig: Point to a structure used to get periodic alarm configuration
 * @return ERR_SUCCESS: If the operation was success
 *         ERR_ERROR: If the operation was fail
 */
errcode_t RTC_GetPeriodicAlarmConfig(uint32_t instance, rtc_periodic_alarm_config_t* alarmConfig);

/*!
 * @brief Set overflow of RTC according to configuration passed as parameter
 *
 * @param[in] instance: Number of RTC
 * @param[out] overflowConfig: Overflow configuration
 * @return ERR_SUCCESS: If the operation was success
 *         ERR_ERROR: If the operation was fail
 */
void RTC_ConfigOverflow(uint32_t instance, rtc_overflow_config_t* overflowConfig);

/*!
 * @brief Convert seconds to Time/Date
 *
 * @param[in] seconds: Point to seconds to be converted
 * @param[out] timeDate: Point to a structure used to get Time/Date
 * @return None
 */
void RTC_ConvertSecondsToTimeDate(const uint32_t* seconds, rtc_timedate_t* timeDate);

/*!
 * @brief Convert Time/Date to seconds
 *
 * @param[in] timeDate: Point to Time/Date to be converted
 * @param[out] seconds: Point to a structure used to get seconds
 * @return None
 */
void RTC_ConvertTimeDateToSeconds(const rtc_timedate_t* timeDate, uint32_t* seconds);

/*!
 * @brief Check if the Time/Date is correct
 *
 * @param[in] timeDate: Point to Time/Date to be checked
 * @return True if format of Time/Date is correct, false if not
 */
bool RTC_IsTimeDateCorrectFormat(const rtc_timedate_t* timeDate);

/*!
 * @brief Check if the given year is leap
 *
 * @param[in] year: year to be checked
 * @return True if format of year is leap, false if not
 */
bool RTC_IsLeapYear(uint32_t year);

/*!
 * @brief Config ICM trigger function which trigger ADC to sample when alarm or periodic-alarm event occur
 *
 * @param[in] instance: Number of RTC
 * @param[in] enable: True to enable trigger ADC function, false if not
 * @return None
 */
void RTC_ConfigICMTrigger(uint32_t instance, bool enable);

/*!
 * @brief Check if ICM trigger function is enabled
 *
 * @param[in] instance: Number of RTC
 * @return true: trigger function is enabled
 *         false: trigger function is disabled
 */
bool RTC_IsICMTriggerEnabled(uint32_t instance);

/*!
 * @brief Interrupt handler of RTC
 *
 * @param[in] instance: Number of RTC
 * @return None
 */
void RTC_IRQHandlerProcess(uint32_t instance);

#if defined(__cplusplus)
}
#endif

/*! @} */

#endif /* RTC_DRV_H */

/*******EOF********************************************************************/
